// xlocmon internal header (from <locale>)
#pragma once
#ifndef _XLOCMON_
#define _XLOCMON_
#ifndef RC_INVOKED
#include <xlocnum>

#pragma pack(push, _CRT_PACKING)
#pragma warning(push, _STL_WARNING_LEVEL)
#pragma warning(disable : _STL_DISABLED_WARNINGS)
_STL_DISABLE_CLANG_WARNINGS
#pragma push_macro("new")
#undef new

_STD_BEGIN
// STRUCT money_base
struct money_base : public locale::facet { // ultimate base class for moneypunct
    enum { // constants for different format codes
        symbol = '$',
        sign   = '+',
        space  = ' ',
        value  = 'v',
        none   = 'x'
    };
    using part = int;

    struct pattern { // four-part formats for monetary text
        char field[4];
    };

    money_base(size_t _Refs = 0) : locale::facet(_Refs) { // default constructor
    }
};

// CLASS TEMPLATE _Mpunct
template <class _Elem>
class _Mpunct : public money_base { // common base class for moneypunct<_Elem, false/true>
public:
    friend _Tidy_guard<_Mpunct>;

public:
    using char_type   = _Elem;
    using string_type = basic_string<_Elem, char_traits<_Elem>, allocator<_Elem>>;

    _Elem decimal_point() const { // return decimal point
        return do_decimal_point();
    }

    _Elem thousands_sep() const { // return thousands separator
        return do_thousands_sep();
    }

    string grouping() const { // return grouping string
        return do_grouping();
    }

    string_type curr_symbol() const { // return currency symbol string
        return do_curr_symbol();
    }

    string_type positive_sign() const { // return plus sign
        return do_positive_sign();
    }

    string_type negative_sign() const { // return minus sign
        return do_negative_sign();
    }

    int frac_digits() const { // return number of fraction digits
        return do_frac_digits();
    }

    pattern pos_format() const { // return format for positive values
        return do_pos_format();
    }

    pattern neg_format() const { // return format for negative values
        return do_neg_format();
    }

    explicit _Mpunct(size_t _Refs, bool _Intl)
        : money_base(_Refs), _International(_Intl) { // construct from current locale
        _BEGIN_LOCINFO(_Lobj)
        _Init(_Lobj);
        _END_LOCINFO()
    }

    _Mpunct(const _Locinfo& _Lobj, size_t _Refs, bool _Intl, bool _Isdef = false)
        : money_base(_Refs), _International(_Intl) { // construct from specified locale
        _Init(_Lobj, _Isdef);
    }

protected:
    _Mpunct(const char* _Locname, size_t _Refs, bool _Intl, bool _Isdef = false)
        : money_base(_Refs), _International(_Intl) { // construct from specified locale
        _BEGIN_LOCINFO(_Lobj(_Locname))
        _Init(_Lobj, _Isdef);
        _END_LOCINFO()
    }

    virtual __CLR_OR_THIS_CALL ~_Mpunct() noexcept { // destroy the object
        _Tidy();
    }

    template <class _Elem2>
    void _Getvals(_Elem2, const lconv* _Ptr) { // get values
        _Currencysign = _Maklocstr(
            _International ? _Ptr->int_curr_symbol : _Ptr->currency_symbol, static_cast<_Elem2*>(nullptr), _Cvt);
        _Plussign = _Maklocstr(
            4 < (unsigned int) _Ptr->p_sign_posn ? "" : _Ptr->positive_sign, static_cast<_Elem2*>(nullptr), _Cvt);
        _Minussign = _Maklocstr(
            4 < (unsigned int) _Ptr->n_sign_posn ? "-" : _Ptr->negative_sign, static_cast<_Elem2*>(nullptr), _Cvt);
        _Decimalpoint = _Maklocchr(_Ptr->mon_decimal_point[0], static_cast<_Elem2*>(nullptr), _Cvt);
        _Kseparator   = _Maklocchr(_Ptr->mon_thousands_sep[0], static_cast<_Elem2*>(nullptr), _Cvt);
    }

    void _Getvals(wchar_t, const lconv* _Ptr) { // get values
        _Currencysign = (const _Elem*) _Maklocwcs(_International ? _Ptr->_W_int_curr_symbol : _Ptr->_W_currency_symbol);
        _Plussign     = (const _Elem*) _Maklocwcs(4 < (unsigned int) _Ptr->p_sign_posn ? L"" : _Ptr->_W_positive_sign);
        _Minussign    = (const _Elem*) _Maklocwcs(4 < (unsigned int) _Ptr->n_sign_posn ? L"-" : _Ptr->_W_negative_sign);
        _Decimalpoint = (_Elem) _Ptr->_W_mon_decimal_point[0];
        _Kseparator   = (_Elem) _Ptr->_W_mon_thousands_sep[0];
    }

    void _Init(const _Locinfo& _Lobj, bool _Isdef = false) { // initialize from _Lobj
        _Cvt              = _Lobj._Getcvt();
        const lconv* _Ptr = _Lobj._Getlconv();

        _Grouping     = nullptr;
        _Currencysign = nullptr;
        _Plussign     = nullptr;
        _Minussign    = nullptr;

        _Tidy_guard<_Mpunct> _Guard{this};
        _Grouping = _Maklocstr(_Ptr->mon_grouping, static_cast<char*>(nullptr), _Cvt);
        _Getvals((_Elem) 0, _Ptr);
        _Guard._Target = nullptr;

        _Fracdigits = _International ? _Ptr->int_frac_digits : _Ptr->frac_digits;
        if (_Fracdigits < 0 || CHAR_MAX <= _Fracdigits) {
            _Fracdigits = 0;
        }

        _Makpat(_Plusformat, static_cast<unsigned int>(_Ptr->p_sep_by_space),
            static_cast<unsigned int>(_Ptr->p_cs_precedes), static_cast<unsigned int>(_Ptr->p_sign_posn));
        _Makpat(_Minusformat, static_cast<unsigned int>(_Ptr->n_sep_by_space),
            static_cast<unsigned int>(_Ptr->n_cs_precedes), static_cast<unsigned int>(_Ptr->n_sign_posn));

        if (_Isdef) { // apply defaults for required facets
            _CSTD memcpy(&_Plusformat, "$+xv", 4);
            _CSTD memcpy(&_Minusformat, "$+xv", 4);
        }
    }

    virtual _Elem __CLR_OR_THIS_CALL do_decimal_point() const { // return decimal point
        return _Decimalpoint;
    }

    virtual _Elem __CLR_OR_THIS_CALL do_thousands_sep() const { // return thousands separator
        return _Kseparator;
    }

    virtual string __CLR_OR_THIS_CALL do_grouping() const { // return grouping string
        return string(_Grouping);
    }

    virtual string_type __CLR_OR_THIS_CALL do_curr_symbol() const { // return currency symbol string
        return string_type(_Currencysign);
    }

    virtual string_type __CLR_OR_THIS_CALL do_positive_sign() const { // return plus sign
        return string_type(_Plussign);
    }

    virtual string_type __CLR_OR_THIS_CALL do_negative_sign() const { // return minus sign
        return string_type(_Minussign);
    }

    virtual int __CLR_OR_THIS_CALL do_frac_digits() const { // return number of fraction digits
        return _Fracdigits;
    }

    virtual pattern __CLR_OR_THIS_CALL do_pos_format() const { // return format for positive values
        return _Plusformat;
    }

    virtual pattern __CLR_OR_THIS_CALL do_neg_format() const { // return format for negative values
        return _Minusformat;
    }

private:
    void _Makpat(pattern& _Pattern, unsigned int _Sepbyspace, unsigned int _Symbolprecedes,
        unsigned int _Signposition) { // make format pattern from locale information
        const char* _Ptr = _International || 2 < _Sepbyspace || 1 < _Symbolprecedes || 4 < _Signposition
                               ? "$+xv" // international or bad parameters
                               : &("+v$x"
                                   "+v$x"
                                   "v$+x"
                                   "v+$x"
                                   "v$+x"
                                   "+$vx"
                                   "+$vx"
                                   "$v+x"
                                   "+$vx"
                                   "$+vx"
                                   "+v $"
                                   "+v $"
                                   "v $+"
                                   "v +$"
                                   "v $+"
                                   "+$ v"
                                   "+$ v"
                                   "$ v+"
                                   "+$ v"
                                   "$+ v"
                                   "+xv$"
                                   "+ v$"
                                   "v$ +"
                                   "v+ $"
                                   "v$ +"
                                   "+x$v"
                                   "+ $v"
                                   "$v +"
                                   "+ $v"
                                   "$ +v")[_Signposition * 4 // pick even/odd column
                                           + _Symbolprecedes * 20 // pick even/odd row
                                           + _Sepbyspace * 40]; // pick first/second/third group

        _CSTD memcpy(_Pattern.field, _Ptr, sizeof(_Pattern.field));
    }

    void _Tidy() noexcept { // free all storage
        _CSTD free((void*) _Grouping);
        _CSTD free((void*) _Currencysign);
        _CSTD free((void*) _Plussign);
        _CSTD free((void*) _Minussign);
    }

    const char* _Grouping; // grouping string, "" for "C" locale
    _Elem _Decimalpoint; // decimal point, '\0' for "C" locale
    _Elem _Kseparator; // thousands separator, '\0' for "C" locale
    const _Elem* _Currencysign; // currency symbol, "" for "C" locale
    const _Elem* _Plussign; // plus sign, "" for "C" locale
    const _Elem* _Minussign; // minus sign, "-" for "C" locale
    int _Fracdigits; // number of fraction digits, 0 for "C" locale
    pattern _Plusformat; // positive format, "$+vx" for "C" locale
    pattern _Minusformat; // negative format, "$+vx" for "C" locale
    bool _International; // true if international format

    _Locinfo::_Cvtvec _Cvt; // conversion information
};

// CLASS TEMPLATE moneypunct
template <class _Elem,
    bool _Intl = false>
class moneypunct : public _Mpunct<_Elem> { // facet for defining monetary punctuation text
public:
    static_assert(!_ENFORCE_FACET_SPECIALIZATIONS || _Is_any_of_v<_Elem, char, wchar_t, unsigned short>,
        _FACET_SPECIALIZATION_MESSAGE);

    _PGLOBAL _CRTIMP2_PURE_IMPORT static const bool intl; // true if international
    __PURE_APPDOMAIN_GLOBAL _CRTIMP2_PURE_IMPORT static locale::id id; // unique facet id

    explicit moneypunct(size_t _Refs = 0) : _Mpunct<_Elem>(_Refs, _Intl) { // construct from current locale
    }

    moneypunct(const _Locinfo& _Lobj, size_t _Refs = 0, bool _Isdef = false)
        : _Mpunct<_Elem>(_Lobj, _Refs, _Intl, _Isdef) { // construct from specified locale
    }

    static size_t _Getcat(const locale::facet** _Ppf = nullptr,
        const locale* _Ploc = nullptr) { // return locale category mask and construct standard facet
        if (_Ppf != nullptr && *_Ppf == nullptr) {
            *_Ppf = new moneypunct<_Elem, _Intl>(_Locinfo(_Ploc->c_str()), 0, true);
        }

        return _X_MONETARY;
    }

protected:
    moneypunct(const char* _Locname, size_t _Refs = 0)
        : _Mpunct<_Elem>(_Locname, _Refs, _Intl) { // construct from specified locale
    }

    virtual __CLR_OR_THIS_CALL ~moneypunct() noexcept { // destroy the object
    }
};

#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdllimport-static-field-def"
#endif // __clang__

// STATIC moneypunct::intl OBJECT
template <class _Elem, bool _Intl>
_PGLOBAL const bool moneypunct<_Elem, _Intl>::intl = _Intl;

// STATIC moneypunct::id OBJECT
template <class _Elem, bool _Intl>
__PURE_APPDOMAIN_GLOBAL locale::id moneypunct<_Elem, _Intl>::id;

#ifdef __clang__
#pragma clang diagnostic pop
#endif // __clang__

// CLASS TEMPLATE moneypunct_byname
template <class _Elem, bool _Intl = false>
class moneypunct_byname : public moneypunct<_Elem, _Intl> { // moneypunct for named locale
public:
    static_assert(!_ENFORCE_FACET_SPECIALIZATIONS || _Is_any_of_v<_Elem, char, wchar_t>, _FACET_SPECIALIZATION_MESSAGE);

    explicit moneypunct_byname(const char* _Locname, size_t _Refs = 0)
        : moneypunct<_Elem, _Intl>(_Locname, _Refs) { // construct for named locale
    }

    explicit moneypunct_byname(const string& _Str, size_t _Refs = 0)
        : moneypunct<_Elem, _Intl>(_Str.c_str(), _Refs) { // construct for named locale
    }

protected:
    virtual __CLR_OR_THIS_CALL ~moneypunct_byname() noexcept { // destroy the object
    }
};

// CLASS TEMPLATE money_get
template <class _Elem, class _InIt = istreambuf_iterator<_Elem, char_traits<_Elem>>>
class money_get : public locale::facet { // facet for converting text to encoded monetary amounts
    using _Mypunct0 = moneypunct<_Elem, false>;
    using _Mypunct1 = moneypunct<_Elem, true>;

public:
    static_assert(!_ENFORCE_FACET_SPECIALIZATIONS || _Is_any_of_v<_Elem, char, wchar_t, unsigned short>,
        _FACET_SPECIALIZATION_MESSAGE);

    using char_type   = _Elem;
    using iter_type   = _InIt;
    using string_type = basic_string<_Elem, char_traits<_Elem>, allocator<_Elem>>;

    _InIt get(_InIt _First, _InIt _Last, bool _Intl, ios_base& _Iosbase, ios_base::iostate& _State,
        long double& _Val) const { // get long double from [_First, _Last) into _Val
        return do_get(_First, _Last, _Intl, _Iosbase, _State, _Val);
    }

    _InIt get(_InIt _First, _InIt _Last, bool _Intl, ios_base& _Iosbase, ios_base::iostate& _State,
        string_type& _Val) const { // get string_type from [_First, _Last) into _Val
        return do_get(_First, _Last, _Intl, _Iosbase, _State, _Val);
    }

    __PURE_APPDOMAIN_GLOBAL _CRTIMP2_PURE_IMPORT static locale::id id; // unique facet id

    explicit money_get(size_t _Refs = 0) : locale::facet(_Refs) { // construct from current locale
        _BEGIN_LOCINFO(_Lobj)
        _Init(_Lobj);
        _END_LOCINFO()
    }

    money_get(const _Locinfo& _Lobj, size_t _Refs = 0) : locale::facet(_Refs) { // construct from specified locale
        _Init(_Lobj);
    }

    static size_t _Getcat(const locale::facet** _Ppf = nullptr,
        const locale* _Ploc = nullptr) { // return locale category mask and construct standard facet
        if (_Ppf != nullptr && *_Ppf == nullptr) {
            *_Ppf = new money_get<_Elem, _InIt>(_Locinfo(_Ploc->c_str()));
        }

        return _X_MONETARY;
    }

protected:
    virtual __CLR_OR_THIS_CALL ~money_get() noexcept { // destroy the object
    }

    void _Init(const _Locinfo&) { // initialize from _Locinfo object
    }

    virtual _InIt __CLR_OR_THIS_CALL do_get(_InIt _First, _InIt _Last, bool _Intl, ios_base& _Iosbase,
        ios_base::iostate& _State,
        long double& _Val) const { // get long double from [_First, _Last) into _Val
        _Elem _Atoms[sizeof("0123456789-")];
        string _Str = _Getmfld(_First, _Last, _Intl, _Iosbase, _Atoms);

        if (_First == _Last) {
            _State |= ios_base::eofbit;
        }

        if (_Str.size() == 0) {
            _State |= ios_base::failbit; // _Getmfld failed
        } else { // convert to long double
            const char* _Eb = _Str.c_str();
            char* _Ep;
            int _Errno             = 0;
            const long double _Ans = _Stodx_v2(_Eb, &_Ep, 0, &_Errno); // convert and "widen" double to long double

            if (_Ep == _Eb || _Errno != 0) {
                _State |= ios_base::failbit;
            } else {
                _Val = _Ans; // deliver value
            }
        }
        return _First;
    }

    virtual _InIt __CLR_OR_THIS_CALL do_get(_InIt _First, _InIt _Last, bool _Intl, ios_base& _Iosbase,
        ios_base::iostate& _State,
        string_type& _Val) const { // get string_type from [_First, _Last) into _Val
        _Elem _Atoms[sizeof("0123456789-")];
        string _Str = _Getmfld(_First, _Last, _Intl, _Iosbase, _Atoms);
        size_t _Len = _Str.size();

        if (_First == _Last) {
            _State |= ios_base::eofbit;
        }

        if (_Len == 0) {
            _State |= ios_base::failbit; // _Getmfld failed
        } else { // deliver value
            size_t _Idx = 0;
            _Val.resize(_Len);
            if (_Str[0] == '-') {
                _Val[_Idx++] = _Atoms[10];
            }

            for (; _Idx < _Len; ++_Idx) {
                _Val[_Idx] = _Atoms[_Str[_Idx] - '0']; // map digits
            }
        }
        return _First;
    }

private:
    string _Getmfld(_InIt& _First, _InIt& _Last, bool _Intl, ios_base& _Iosbase,
        _Elem (&_Atoms)[12]) const { // get monetary field from [_First, _Last) into string_type
        _Adl_verify_range(_First, _Last);
        const _Mpunct<_Elem>* _Ppunct_fac;
        if (_Intl) {
            _Ppunct_fac = _STD addressof(_STD use_facet<_Mypunct1>(_Iosbase.getloc())); // international
        } else {
            _Ppunct_fac = _STD addressof(_STD use_facet<_Mypunct0>(_Iosbase.getloc())); // local
        }

        bool _Bad = false, _Neg = false;
        string_type _Sign;
        const money_base::pattern _Pattern = _Ppunct_fac->neg_format();
        string _Val;
        size_t _Idx;
        static constexpr char _Src[]   = {"0123456789-"};
        const ctype<_Elem>& _Ctype_fac = _STD use_facet<ctype<_Elem>>(_Iosbase.getloc());
        _Ctype_fac.widen(&_Src[0], &_Src[sizeof(_Src)], _Atoms);

        for (size_t _Off = 0; !_Bad && _Off < 4; ++_Off) {
            switch (_Pattern.field[_Off]) { // parse a format component
            case money_base::symbol: { // parse currency symbol
                string_type _Symbol = _Ppunct_fac->curr_symbol();
                typename string_type::const_iterator _Source;

                if ((!(_Iosbase.flags() & ios_base::showbase) && _First != _Last && *_First != *_Symbol.c_str())
                    || (_Off == 3 && _Sign.size() <= 1
                           && (_First == _Last || *_First != *_Symbol.c_str()))) { // showbase ==> mandatory symbol
                                                                                   // or
                                                                                   // currency symbol optional at end
                    _Symbol.erase();
                }

                _Source = _Symbol.begin();
                while (_First != _Last && _Source != _Symbol.end()
                       && *_First == *_Source) { // still matching currency symbol
                    ++_Source;
                    ++_First;
                }

                if (_Source != _Symbol.end()) {
                    _Bad = true; // currency symbol match failed
                }
                break;
            }

            case money_base::sign: // parse sign
                if (_First != _Last) {
                    if (0 < _Ppunct_fac->positive_sign().size()
                        && _Ppunct_fac->positive_sign()[0] == *_First) { // match positive sign
                        ++_First;
                        _Sign = _Ppunct_fac->positive_sign();
                    } else if (0 < _Ppunct_fac->negative_sign().size()
                               && _Ppunct_fac->negative_sign()[0] == *_First) { // match negative sign
                        ++_First;
                        _Sign = _Ppunct_fac->negative_sign();
                        _Neg  = true;
                    } else if (0 != _Ppunct_fac->positive_sign().size() && 0 == _Ppunct_fac->negative_sign().size()) {
                        _Neg = true;
                    }
                }

                break; // sign match can't fail

            case money_base::value: { // parse value field
                int _Fracdigseen        = 0;
                int _Fracdigits         = _Ppunct_fac->frac_digits();
                const string _Grouping  = _Ppunct_fac->grouping();
                const _Elem _Kseparator = _Grouping.size() == 0 ? (_Elem) 0 : _Ppunct_fac->thousands_sep();

                if (_Kseparator == (_Elem) 0 || CHAR_MAX <= (unsigned char) *_Grouping.c_str()) {
                    for (; _First != _Last && (_Idx = _Find_elem(_Atoms, *_First)) < 10; ++_First) {
                        _Val += _Src[_Idx]; // no grouping, just gather digits
                    }
                } else { // grouping specified, gather digits and group sizes
                    string _Groups;
                    _Groups.push_back('\0');
                    size_t _Group = 0;

                    for (; _First != _Last; ++_First) {
                        if ((_Idx = _Find_elem(_Atoms, *_First)) < 10) { // got a digit, add to group size
                            _Val += _Src[_Idx];
                            if (_Groups[_Group] != CHAR_MAX) {
                                ++_Groups[_Group];
                            }
                        } else if (_Groups[_Group] == '\0' || *_First != _Kseparator) {
                            break; // not a group separator, done
                        } else { // add a new group to _Groups string
                            _Groups.push_back('\0');
                            ++_Group;
                        }
                    }

                    if (_Group != 0) { // thousands separators seen
                        if ('\0' < _Groups[_Group]) {
                            ++_Group; // add trailing group to group count
                        } else {
                            _Bad = true; // trailing separator, fail
                        }
                    }

                    for (const char* _Pg = _Grouping.c_str(); !_Bad && 0 < _Group;) {
                        if (*_Pg == CHAR_MAX) {
                            break; // end of grouping constraints to check
                        }

                        if ((0 < --_Group && *_Pg != _Groups[_Group]) || (0 == _Group && *_Pg < _Groups[_Group])) {
                            _Bad = true; // bad group size, fail
                        } else if ('\0' < _Pg[1]) {
                            ++_Pg; // group size okay, advance to next test
                        }
                    }

                    if (_Bad) {
                        break; // bad grouping, give up
                    }
                }

                const _Elem _Point = _Ppunct_fac->decimal_point();
                if (_First != _Last && _Point != (_Elem) 0
                    && *_First == _Point) { // seen decimal point, gather fraction digits
                    while (
                        ++_First != _Last && _Fracdigseen < _Fracdigits && (_Idx = _Find_elem(_Atoms, *_First)) < 10) {
                        _Val += _Src[_Idx];
                        ++_Fracdigseen;
                    }

                    if (_Fracdigseen < _Fracdigits) {
                        _Bad = true; // short fraction
                    }
                }

                if (_Val.size() == 0) {
                    _Bad = true; // fail if no elements parsed
                } else {
                    for (; _Fracdigseen < _Fracdigits; ++_Fracdigseen) {
                        _Val += '0'; // pad out fraction with zeros
                    }
                }

                break;
            }

            case money_base::space:
            case money_base::none: { // parse optional space
                if (_Off == 3) {
                    break; // ignore space at end
                }

                bool _Seen = false;

                for (; _First != _Last && _Ctype_fac.is(ctype_base::space, *_First); ++_First) {
                    _Seen = true; // skip any space
                }

                if (_Pattern.field[_Off] == money_base::space && !_Seen) {
                    _Bad = true; // fail if no space seen
                }
            } // parse optional space
            } // switch
        }

        if (!_Bad && 1 < _Sign.size()) { // match rest of sign string
            auto _Source = _Sign.begin();

            while (++_Source != _Sign.end() && _First != _Last && *_First == *_Source) {
                ++_First;
            }

            if (_Source != _Sign.end()) {
                _Bad = true; // rest of sign doesn't match, fail
            }
        }

        if (_Bad) {
            _Val.erase(); // bad input, return empty string
        } else if (_Neg) {
            _Val.insert((size_t) 0, (size_t) 1, '-'); // minus sign
        }

        return _Val;
    }
};

// STATIC money_get::id OBJECT
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdllimport-static-field-def"
#endif // __clang__

template <class _Elem, class _InIt>
__PURE_APPDOMAIN_GLOBAL locale::id money_get<_Elem, _InIt>::id;

#ifdef __clang__
#pragma clang diagnostic pop
#endif // __clang__

// CLASS TEMPLATE money_put
template <class _Elem, class _OutIt = ostreambuf_iterator<_Elem, char_traits<_Elem>>>
class money_put : public locale::facet { // facet for converting encoded monetary amounts to text
    using _Mypunct0 = moneypunct<_Elem, false>;
    using _Mypunct1 = moneypunct<_Elem, true>;

public:
    static_assert(!_ENFORCE_FACET_SPECIALIZATIONS || _Is_any_of_v<_Elem, char, wchar_t, unsigned short>,
        _FACET_SPECIALIZATION_MESSAGE);

    using char_type   = _Elem;
    using iter_type   = _OutIt;
    using string_type = basic_string<_Elem, char_traits<_Elem>, allocator<_Elem>>;

    _OutIt put(_OutIt _Dest, bool _Intl, ios_base& _Iosbase, _Elem _Fill,
        long double _Val) const { // put long double to _Dest
        return do_put(_Dest, _Intl, _Iosbase, _Fill, _Val);
    }

    _OutIt put(_OutIt _Dest, bool _Intl, ios_base& _Iosbase, _Elem _Fill,
        const string_type& _Val) const { // put string_type to _Dest
        return do_put(_Dest, _Intl, _Iosbase, _Fill, _Val);
    }

    __PURE_APPDOMAIN_GLOBAL _CRTIMP2_PURE_IMPORT static locale::id id; // unique facet id

    explicit money_put(size_t _Refs = 0) : locale::facet(_Refs) { // construct from current locale
        _BEGIN_LOCINFO(_Lobj)
        _Init(_Lobj);
        _END_LOCINFO()
    }

    money_put(const _Locinfo& _Lobj, size_t _Refs = 0) : locale::facet(_Refs) { // construct from specified locale
        _Init(_Lobj);
    }

    static size_t _Getcat(const locale::facet** _Ppf = nullptr,
        const locale* _Ploc = nullptr) { // return locale category mask and construct standard facet
        if (_Ppf != nullptr && *_Ppf == nullptr) {
            *_Ppf = new money_put<_Elem, _OutIt>(_Locinfo(_Ploc->c_str()));
        }

        return _X_MONETARY;
    }

protected:
    virtual __CLR_OR_THIS_CALL ~money_put() noexcept { // destroy the object
    }

    void _Init(const _Locinfo&) { // initialize from _Locinfo object
    }

    virtual _OutIt __CLR_OR_THIS_CALL do_put(_OutIt _Dest, bool _Intl, ios_base& _Iosbase, _Elem _Fill,
        long double _Val) const { // put long double to _Dest
        bool _Negative = false;
        if (_Val < 0) {
            _Negative = true;
            _Val      = -_Val;
        }

        size_t _Exp;
        for (_Exp = 0; 1e35 <= _Val && _Exp < 5000; _Exp += 10) {
            _Val /= 1e10; // drop 10 zeros before decimal point
        }

        char _Buf[40];

        // convert to chars:
        const auto _Count = static_cast<size_t>(_CSTD sprintf_s(_Buf, sizeof(_Buf), "%.0Lf", _Val));

        if (_Count < 0) {
            return _Dest; // bad conversion, give up
        }

        const ctype<_Elem>& _Ctype_fac = _STD use_facet<ctype<_Elem>>(_Iosbase.getloc());
        const _Elem _E0                = _Ctype_fac.widen('0');

        string_type _Val2(_Count, (_Elem) 0);
        _Ctype_fac.widen(&_Buf[0], &_Buf[_Count], &_Val2[0]);
        _Val2.append(_Exp, _E0); // scale by trailing zeros
        return _Putmfld(_Dest, _Intl, _Iosbase, _Fill, _Negative, _Val2, _E0);
    }

    virtual _OutIt __CLR_OR_THIS_CALL do_put(_OutIt _Dest, bool _Intl, ios_base& _Iosbase, _Elem _Fill,
        const string_type& _Val) const { // put string_type to _Dest
        static constexpr char _Src[] = {"0123456789-"};
        _Elem _Atoms[sizeof(_Src)];
        const ctype<_Elem>& _Ctype_fac = _STD use_facet<ctype<_Elem>>(_Iosbase.getloc());
        _Ctype_fac.widen(&_Src[0], &_Src[sizeof(_Src)], _Atoms);

        bool _Negative = false;
        size_t _Idx0   = 0;
        if (!_Val.empty() && _Val[0] == _Atoms[10]) { // strip off '-'
            _Negative = true;
            ++_Idx0;
        }

        size_t _Size = _Val.size();
        size_t _Idx  = _Idx0;
        for (; _Idx < _Size && _Find_elem(_Atoms, _Val[_Idx]) < 10; ++_Idx) { // count digits
        }

        string_type _Val2(&_Val[_Idx0], (size_t)(_Idx - _Idx0));
        if (_Val2.empty()) { // replace empty digit string with '0'
            _Val2.push_back(_Atoms[0]);
        }

        return _Putmfld(_Dest, _Intl, _Iosbase, _Fill, _Negative, _Val2, _Atoms[0]);
    }

private:
    _OutIt _Putmfld(_OutIt _Dest, bool _Intl, ios_base& _Iosbase, _Elem _Fill, bool _Neg, string_type _Val,
        _Elem _E0) const { // put string_type with just digits to _Dest
        const _Mpunct<_Elem>* _Ppunct_fac;
        if (_Intl) {
            _Ppunct_fac = _STD addressof(_STD use_facet<_Mypunct1>(_Iosbase.getloc())); // international
        } else {
            _Ppunct_fac = _STD addressof(_STD use_facet<_Mypunct0>(_Iosbase.getloc())); // local
        }

        const string _Grouping = _Ppunct_fac->grouping();
        int _Ifracdigits       = _Ppunct_fac->frac_digits();
        const auto _Fracdigits = static_cast<unsigned int>(_Ifracdigits < 0 ? -_Ifracdigits : _Ifracdigits);

        if (_Val.size() <= _Fracdigits) {
            _Val.insert((size_t) 0, _Fracdigits - _Val.size() + 1, _E0);
        } else if (*_Grouping.c_str() != CHAR_MAX
                   && '\0' < *_Grouping.c_str()) { // grouping specified, add thousands separators
            const _Elem _Kseparator = _Ppunct_fac->thousands_sep();
            const char* _Pg         = _Grouping.c_str();
            size_t _Off             = _Val.size() - _Fracdigits; // start of fraction

            while (
                *_Pg != CHAR_MAX && '\0' < *_Pg && (size_t) *_Pg < _Off) { // add a thousands separator, right to left
                _Val.insert(_Off -= *_Pg, (size_t) 1, _Kseparator);
                if ('\0' < _Pg[1]) {
                    ++_Pg; // not last group, advance
                }
            }
        }

        money_base::pattern _Pattern;
        string_type _Sign;
        if (_Neg) { // negative value, choose appropriate format and sign
            _Pattern = _Ppunct_fac->neg_format();
            _Sign    = _Ppunct_fac->negative_sign();
        } else { // positive value, choose appropriate format and sign
            _Pattern = _Ppunct_fac->pos_format();
            _Sign    = _Ppunct_fac->positive_sign();
        }

        string_type _Symbol;
        if (_Iosbase.flags() & ios_base::showbase) {
            _Symbol = _Ppunct_fac->curr_symbol(); // showbase ==> show $
        }

        bool _Intern = false;
        size_t _Fillcount, _Off;
        for (_Fillcount = 0, _Off = 0; _Off < 4; ++_Off) {
            switch (_Pattern.field[_Off]) { // accumulate total length in _Fillcount
            case money_base::symbol: // count currency symbol size
                _Fillcount += _Symbol.size();
                break;

            case money_base::sign: // count sign size
                _Fillcount += _Sign.size();
                break;

            case money_base::value: // count value field size
                _Fillcount += _Val.size() + (0 < _Fracdigits ? 1 : 0)
                              + (_Val.size() <= _Fracdigits ? _Fracdigits - _Val.size() + 1 : 0);
                break;

            case money_base::space: // count space size
                ++_Fillcount; // at least one space
                // fall through

            case money_base::none: // count space size
                if (_Off != 3) {
                    _Intern = true; // optional internal fill
                }

                break;
            }
        }

        _Fillcount = _Iosbase.width() <= 0 || (size_t) _Iosbase.width() <= _Fillcount
                         ? 0
                         : (size_t) _Iosbase.width() - _Fillcount;

        ios_base::fmtflags _Afl = _Iosbase.flags() & ios_base::adjustfield;
        if (_Afl != ios_base::left && (_Afl != ios_base::internal || !_Intern)) { // put leading fill
            _Dest      = _Rep(_Dest, _Fill, _Fillcount);
            _Fillcount = 0;
        }

        for (_Off = 0; _Off < 4; ++_Off) {
            switch (_Pattern.field[_Off]) { // put components as specified by _Pattern
            case money_base::symbol: // put currency symbol
                _Dest = _Put(_Dest, _Symbol.begin(), _Symbol.size());
                break;

            case money_base::sign: // put sign
                if (0 < _Sign.size()) {
                    _Dest = _Put(_Dest, _Sign.begin(), 1);
                }

                break;

            case money_base::value: // put value field
                if (_Fracdigits == 0) {
                    _Dest = _Put(_Dest, _Val.begin(),
                        _Val.size()); // no fraction part
                } else if (_Val.size() <= _Fracdigits) { // put leading zero, all fraction digits
                    *_Dest++ = _E0;
                    *_Dest++ = _Ppunct_fac->decimal_point();
                    _Dest    = _Rep(_Dest, _E0,
                        _Fracdigits - _Val.size()); // insert zeros
                    _Dest    = _Put(_Dest, _Val.begin(), _Val.size());
                } else { // put both integer and fraction parts
                    _Dest    = _Put(_Dest, _Val.begin(),
                        _Val.size() - _Fracdigits); // put integer part
                    *_Dest++ = _Ppunct_fac->decimal_point();
                    _Dest    = _Put(_Dest, _Val.end() - static_cast<ptrdiff_t>(_Fracdigits),
                        _Fracdigits); // put fraction part
                }
                break;

            case money_base::space: // put any internal fill
                _Dest = _Rep(_Dest, _Fill, 1);
                // fall through

            case money_base::none: // put any internal fill
                if (_Afl == ios_base::internal) { // put internal fill
                    _Dest      = _Rep(_Dest, _Fill, _Fillcount);
                    _Fillcount = 0;
                }
            }
        }

        if (1 < _Sign.size()) {
            _Dest = _Put(_Dest, _Sign.begin() + 1,
                _Sign.size() - 1); // put remainder of sign
        }

        _Iosbase.width(0);
        return _Rep(_Dest, _Fill, _Fillcount); // put trailing fill
    }

    static _OutIt _Put(_OutIt _Dest, typename string_type::const_iterator _Source,
        size_t _Count) { // put [_Source, _Source + _Count) to _Dest
        for (; 0 < _Count; --_Count, (void) ++_Dest, ++_Source) {
            *_Dest = *_Source;
        }

        return _Dest;
    }

    static _OutIt _Rep(_OutIt _Dest, _Elem _Ch, size_t _Count) { // put _Count * _Ch to _Dest
        for (; 0 < _Count; --_Count, (void) ++_Dest) {
            *_Dest = _Ch;
        }

        return _Dest;
    }
};

// STATIC money_put::id OBJECT
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdllimport-static-field-def"
#endif // __clang__

template <class _Elem, class _OutIt>
__PURE_APPDOMAIN_GLOBAL locale::id money_put<_Elem, _OutIt>::id;

#if defined(_DLL_CPPLIB)

#if !defined(_CRTBLD) || defined(__FORCE_INSTANCE)
template _PGLOBAL const bool moneypunct<char, true>::intl;
template _PGLOBAL const bool moneypunct<char, false>::intl;
template __PURE_APPDOMAIN_GLOBAL locale::id moneypunct<char, true>::id;
template __PURE_APPDOMAIN_GLOBAL locale::id moneypunct<char, false>::id;
template __PURE_APPDOMAIN_GLOBAL locale::id money_get<char, istreambuf_iterator<char, char_traits<char>>>::id;
template __PURE_APPDOMAIN_GLOBAL locale::id money_put<char, ostreambuf_iterator<char, char_traits<char>>>::id;

template _PGLOBAL const bool moneypunct<wchar_t, true>::intl;
template _PGLOBAL const bool moneypunct<wchar_t, false>::intl;
template __PURE_APPDOMAIN_GLOBAL locale::id moneypunct<wchar_t, true>::id;
template __PURE_APPDOMAIN_GLOBAL locale::id moneypunct<wchar_t, false>::id;
template __PURE_APPDOMAIN_GLOBAL locale::id money_get<wchar_t, istreambuf_iterator<wchar_t, char_traits<wchar_t>>>::id;
template __PURE_APPDOMAIN_GLOBAL locale::id money_put<wchar_t, ostreambuf_iterator<wchar_t, char_traits<wchar_t>>>::id;
#endif // !defined(_CRTBLD) || defined(__FORCE_INSTANCE)

#ifdef __FORCE_INSTANCE
template _PGLOBAL const bool moneypunct<unsigned short, true>::intl;
template _PGLOBAL const bool moneypunct<unsigned short, false>::intl;
template __PURE_APPDOMAIN_GLOBAL locale::id moneypunct<unsigned short, true>::id;
template __PURE_APPDOMAIN_GLOBAL locale::id moneypunct<unsigned short, false>::id;
template __PURE_APPDOMAIN_GLOBAL locale::id
    money_get<unsigned short, istreambuf_iterator<unsigned short, char_traits<unsigned short>>>::id;
template __PURE_APPDOMAIN_GLOBAL locale::id
    money_put<unsigned short, ostreambuf_iterator<unsigned short, char_traits<unsigned short>>>::id;
#endif // __FORCE_INSTANCE
#endif // defined(_DLL_CPPLIB)

#ifdef __clang__
#pragma clang diagnostic pop
#endif // __clang__

_STD_END

#pragma pop_macro("new")
_STL_RESTORE_CLANG_WARNINGS
#pragma warning(pop)
#pragma pack(pop)
#endif // RC_INVOKED
#endif // _XLOCMON_

/*
 * Copyright (c) by P.J. Plauger. All rights reserved.
 * Consult your license regarding permissions and restrictions.
V6.50:0009 */
